
package peerToPeerFacebook.proj;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;

import peerToPeerFacebook.src.edu.washington.cs.cse490h.lib.PersistentStorageReader;
import peerToPeerFacebook.src.edu.washington.cs.cse490h.lib.PersistentStorageWriter;
import peerToPeerFacebook.src.edu.washington.cs.cse490h.lib.Utility;

public class UtilityFile
{

    /**
     * This method writes the input text to the file fileName. Old content of the file is overwritten.
     * 
     * @param node, the FBNode reference
     * @param fileName, the filename into which text will be written
     * @param text, String input that needs to be written to the file
     */
    public static void writeToFile(FBNode node, String fileName, String text)
    {
        PersistentStorageWriter writer = null;
        try
        {
            writer = node.getWriter(fileName, false);
            writer.append(text);
            writer.newLine();
            writer.close();
        }
        catch (Exception e)
        {
            System.out.println(" Error while writing to the file + " + fileName);
        }
        finally
        {
            if (writer != null)
                try
                {
                    writer.close();
                }
                catch (IOException e)
                {
                    System.out.println(" Error while closing the file: " + fileName +
                                       " in write function ");
                }
        }
    }

    /**
     * This method reads the string from the specified File
     * 
     * @param node, the FBNode reference
     * @param fileName the input file name
     * @return the String text read from the File
     */
    public static String readFromFile(FBNode node, String fileName)
    {
        if (Utility.fileExists(node, fileName))
        {
            PersistentStorageReader reader = null;
            StringBuilder result = new StringBuilder();
            String line;
            try
            {
                reader = node.getReader(fileName);
                while ((line = reader.readLine()) != null)
                {
                    result.append(line);
                }
                reader.close();
            }
            catch (Exception e)
            {
                System.out.println(" Error while reading from the file: " + fileName);
            }

            finally
            {
                if (reader != null)
                    try
                    {
                        reader.close();
                    }
                    catch (IOException e)
                    {
                        System.out.println(" Error while closing the file " + fileName +
                                           " in the read File method");
                    }
            }
            return result.toString();
        }
        return null;
    }

    /**
     * Static method for writing serializable objects to disk
     * @param node, the reference FBNode
     * @param fileName, the filename into which write needs to be performed
     * @param object, the serializable object 
     */
    protected static <T extends Serializable> void writeToDisk(FBNode node, String fileName, T object)
    {

        OutputStream disk = null;
        // OutputStream tempDisk = null;
        try
        {
            // Convert object to bytes
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(byteOut);
            out.writeObject(object);
            out.close();

            /*
             * // Flush first to temp file. // In case we fail here - we will
             * have correct data stored in our original file tempDisk =
             * getOut(generateTempFileName(fileName));
             * tempDisk.write(byteOut.toByteArray()); tempDisk.close();
             */
            // Now we know that temp file contains valid data. So we can update
            // original file.
            disk = node.getOutputStream(fileName, false);
            disk.write(byteOut.toByteArray());
            disk.close();

        }
        catch (IOException ex)
        {
            System.out.println(" Failed to store to the disk");
        }
    }

    /**
     * The method which reads from the file and returns the serializable object
     * @param node, the reference FBNode
     * @param fileName, the fileName from which read needs to be performed
     * @return the serializable object
     * @throws IOException, throws Exception in case some I/O operation fails
     */
    @SuppressWarnings("unchecked")
    protected static <T extends Serializable> T readFromDisk(FBNode node, String fileName)
            throws IOException
    {

        InputStream in = node.getInputStream(fileName);
        ObjectInputStream dataIn = null;
        T object = null;

        // if file is there, let's read the data and see what happens
        if (in != null)
            try
            {
                dataIn = new ObjectInputStream(in);
                object = (T) dataIn.readObject();
            }
            catch (Exception ex)
            {
                // We failed to read. There could be a lot of reaqsons for that,
                // e.g. file is corrupt. We just report
                // them back and move on
                System.out.println(" Failed to read from the file: " + fileName);
            }
            finally
            {
                in.close();
                if (dataIn != null)
                    dataIn.close();
            }

        return object;
    }

}
